home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gscoord.c < prev    next >
C/C++ Source or Header  |  1996-12-07  |  13KB  |  472 lines

  1. /* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gscoord.c */
  20. /* Coordinate system operators for Ghostscript library */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsccode.h"            /* for gxfont.h */
  25. #include "gxfarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"
  28. #include "gxfont.h"            /* for char_tm */
  29. #include "gxpath.h"            /* for gx_path_translate */
  30. #include "gzstate.h"
  31. #include "gxcoord.h"            /* requires gsmatrix, gsstate */
  32. #include "gxdevice.h"
  33.  
  34. /* Choose whether to enable the rounding code in update_ctm. */
  35. #define ROUND_CTM_FIXED 1
  36.  
  37. /* Forward declarations */
  38. #ifdef DEBUG
  39. #define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
  40. private void near trace_matrix_fixed(P1(const gs_matrix_fixed *));
  41. private void near trace_matrix(P1(const gs_matrix *));
  42. #endif
  43.  
  44. /* Macro for ensuring ctm_inverse is valid */
  45. #ifdef DEBUG
  46. #define print_inverse(pgs)\
  47. if ( gs_debug_c('x') )\
  48.     dprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
  49. #else
  50. #define print_inverse(pgs) DO_NOTHING
  51. #endif
  52. #define ensure_inverse_valid(pgs)\
  53.     if ( !pgs->ctm_inverse_valid )\
  54.        {    int code = ctm_set_inverse(pgs);\
  55.         if ( code < 0 ) return code;\
  56.        }
  57.  
  58. private int
  59. ctm_set_inverse(gs_state *pgs)
  60. {    int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
  61.     print_inverse(pgs);
  62.     if ( code < 0 ) return code;
  63.     pgs->ctm_inverse_valid = true;
  64.     return 0;
  65. }
  66.  
  67. /* Machinery for updating fixed version of ctm. */
  68. /*
  69.  * We (conditionally) adjust the floating point translation
  70.  * so that it exactly matches the (rounded) fixed translation.
  71.  * This avoids certain unpleasant rounding anomalies, such as
  72.  * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
  73.  * not returning 0 0.
  74.  */
  75. #if ROUND_CTM_FIXED
  76. #  define update_t_fixed(mat, t, t_fixed, v)\
  77.     (set_float2fixed_vars((mat).t_fixed, v),\
  78.      set_fixed2float_var((mat).t, (mat).t_fixed))
  79. #else                    /* !ROUND_CTM_FIXED */
  80. #  define update_t_fixed(mat, t, t_fixed, v)\
  81.     ((mat).t = (v),\
  82.      set_float2fixed_vars((mat).t_fixed, (mat).t))
  83. #endif                    /* (!)ROUND_CTM_FIXED */
  84. #define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
  85. #define update_matrix_fixed(mat, xt, yt)\
  86.   ((mat).txy_fixed_valid = (f_fits_in_fixed(xt) && f_fits_in_fixed(yt) ?\
  87.                 (update_t_fixed(mat, tx, tx_fixed, xt),\
  88.                  update_t_fixed(mat, ty, ty_fixed, yt), true) :\
  89.                 ((mat).tx = (xt), (mat).ty = (yt), false)))
  90. #define update_ctm(pgs, xt, yt)\
  91.   (pgs->ctm_inverse_valid = false,\
  92.    pgs->char_tm_valid = false,\
  93.    update_matrix_fixed(pgs->ctm, xt, yt))
  94.  
  95. /* ------ Coordinate system definition ------ */
  96.  
  97. int
  98. gs_initmatrix(gs_state *pgs)
  99. {    gs_matrix imat;
  100.     gs_defaultmatrix(pgs, &imat);
  101.     update_ctm(pgs, imat.tx, imat.ty);
  102.     set_ctm_only(pgs, imat);
  103. #ifdef DEBUG
  104. if ( gs_debug_c('x') )
  105.     dprintf("[x]initmatrix:\n"), trace_ctm(pgs);
  106. #endif
  107.     return 0;
  108. }
  109.  
  110. int
  111. gs_defaultmatrix(const gs_state *pgs, gs_matrix *pmat)
  112. {    gx_device *dev;
  113.     if ( pgs->ctm_default_set )    /* set after Install */
  114.       { *pmat = pgs->ctm_default;
  115.         return 1;
  116.       }
  117.     dev = gs_currentdevice_inline(pgs);
  118.     gs_deviceinitialmatrix(dev, pmat);
  119.     /* Add in the translation for the Margins. */
  120.     pmat->tx += dev->Margins[0] *
  121.       dev->HWResolution[0] / dev->MarginsHWResolution[0];
  122.     pmat->ty += dev->Margins[1] *
  123.       dev->HWResolution[1] / dev->MarginsHWResolution[1];
  124.     return 0;
  125. }
  126.  
  127. int
  128. gs_setdefaultmatrix(gs_state *pgs, const gs_matrix *pmat)
  129. {    if ( pmat == NULL )
  130.       pgs->ctm_default_set = false;
  131.     else
  132.       { pgs->ctm_default = *pmat;
  133.         pgs->ctm_default_set = true;
  134.       }
  135.     return 0;
  136. }
  137.  
  138. int
  139. gs_currentmatrix(const gs_state *pgs, gs_matrix *pmat)
  140. {    *pmat = ctm_only(pgs);
  141.     return 0;
  142. }
  143.  
  144. /* Set the current transformation matrix for rendering text. */
  145. /* Note that this may be based on a font other than the current font. */
  146. int
  147. gs_setcharmatrix(gs_state *pgs, const gs_matrix *pmat)
  148. {    gs_matrix cmat;
  149.     int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
  150.     if ( code < 0 )
  151.       return code;
  152.     update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty);
  153.     char_tm_only(pgs) = cmat;
  154. #ifdef DEBUG
  155. if ( gs_debug_c('x') )
  156.     dprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
  157. #endif
  158.     pgs->char_tm_valid = true;
  159.     return 0;
  160. }
  161.  
  162. /* Read (after possibly computing) the current transformation matrix */
  163. /* for rendering text.  If force=true, update char_tm if it is invalid; */
  164. /* if force=false, don't update char_tm, and return an error code. */
  165. int
  166. gs_currentcharmatrix(gs_state *pgs, gs_matrix *ptm, bool force)
  167. {    if ( !pgs->char_tm_valid )
  168.     {    int code;
  169.         if ( !force )
  170.           return_error(gs_error_undefinedresult);
  171.         code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
  172.         if ( code < 0 )
  173.           return code;
  174.     }
  175.     if ( ptm != NULL )
  176.       *ptm = char_tm_only(pgs);
  177.     return 0;
  178. }
  179.  
  180. int
  181. gs_setmatrix(gs_state *pgs, const gs_matrix *pmat)
  182. {    update_ctm(pgs, pmat->tx, pmat->ty);
  183.     set_ctm_only(pgs, *pmat);
  184. #ifdef DEBUG
  185. if ( gs_debug_c('x') )
  186.     dprintf("[x]setmatrix:\n"), trace_ctm(pgs);
  187. #endif
  188.     return 0;
  189. }
  190.  
  191. int
  192. gs_imager_setmatrix(gs_imager_state *pis, const gs_matrix *pmat)
  193. {    update_matrix_fixed(pis->ctm, pmat->tx, pmat->ty);
  194.     set_ctm_only(pis, *pmat);
  195. #ifdef DEBUG
  196. if ( gs_debug_c('x') )
  197.     dprintf("[x]imager_setmatrix:\n"), trace_ctm(pis);
  198. #endif
  199.     return 0;
  200. }
  201.  
  202. int
  203. gs_settocharmatrix(gs_state *pgs)
  204. {    if ( pgs->char_tm_valid )
  205.     {    pgs->ctm = pgs->char_tm;
  206.         pgs->ctm_inverse_valid = false;
  207.         return 0;
  208.     }
  209.     else
  210.         return_error(gs_error_undefinedresult);
  211. }
  212.  
  213. int
  214. gs_translate(gs_state *pgs, floatp dx, floatp dy)
  215. {    gs_point pt;
  216.     int code;
  217.     if ( (code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0 )
  218.       return code;
  219.     pt.x += pgs->ctm.tx;
  220.     pt.y += pgs->ctm.ty;
  221.     update_ctm(pgs, pt.x, pt.y);
  222. #ifdef DEBUG
  223. if ( gs_debug_c('x') )
  224.     dprintf4("[x]translate: %f %f -> %f %f\n",
  225.          dx, dy, pt.x, pt.y),
  226.     trace_ctm(pgs);
  227. #endif
  228.     return 0;
  229. }
  230.  
  231. int
  232. gs_scale(gs_state *pgs, floatp sx, floatp sy)
  233. {    pgs->ctm.xx *= sx;
  234.     pgs->ctm.xy *= sx;
  235.     pgs->ctm.yx *= sy;
  236.     pgs->ctm.yy *= sy;
  237.     pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
  238. #ifdef DEBUG
  239. if ( gs_debug_c('x') )
  240.     dprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
  241. #endif
  242.     return 0;
  243. }
  244.  
  245. int
  246. gs_rotate(gs_state *pgs, floatp ang)
  247. {    int code = gs_matrix_rotate(&ctm_only(pgs), ang,
  248.                     &ctm_only_writable(pgs));
  249.     pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
  250. #ifdef DEBUG
  251. if ( gs_debug_c('x') )
  252.     dprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
  253. #endif
  254.     return code;
  255. }
  256.  
  257. int
  258. gs_concat(gs_state *pgs, const gs_matrix *pmat)
  259. {    gs_matrix cmat;
  260.     int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
  261.     if ( code < 0 )
  262.       return code;
  263.     update_ctm(pgs, cmat.tx, cmat.ty);
  264.     set_ctm_only(pgs, cmat);
  265. #ifdef DEBUG
  266. if ( gs_debug_c('x') )
  267.     dprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
  268. #endif
  269.     return code;
  270. }
  271.  
  272. /* ------ Coordinate transformation ------ */
  273.  
  274. #define is_skewed(pmat) (!(is_xxyy(pmat) || is_xyyx(pmat)))
  275.  
  276. int
  277. gs_transform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  278. {    return gs_point_transform(x, y, &ctm_only(pgs), pt);
  279. }
  280.  
  281. int
  282. gs_dtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  283. {    return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
  284. }
  285.  
  286. int
  287. gs_itransform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  288. {    /* If the matrix isn't skewed, we get more accurate results */
  289.     /* by using transform_inverse than by using the inverse matrix. */
  290.     if ( !is_skewed(&pgs->ctm) )
  291.        {    return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
  292.        }
  293.     else
  294.        {    ensure_inverse_valid(pgs);
  295.         return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
  296.        }
  297. }
  298.  
  299. int
  300. gs_idtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  301. {    /* If the matrix isn't skewed, we get more accurate results */
  302.     /* by using transform_inverse than by using the inverse matrix. */
  303.     if ( !is_skewed(&pgs->ctm) )
  304.        {    return gs_distance_transform_inverse(dx, dy,
  305.                              &ctm_only(pgs), pt);
  306.        }
  307.     else
  308.        {    ensure_inverse_valid(pgs);
  309.         return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
  310.        }
  311. }
  312.  
  313. int
  314. gs_imager_idtransform(const gs_imager_state *pis, floatp dx, floatp dy,
  315.   gs_point *pt)
  316. {    return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt);
  317. }
  318.  
  319. /* ------ For internal use only ------ */
  320.  
  321. /* Set the translation to a fixed value, and translate any existing path. */
  322. /* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
  323. int
  324. gx_translate_to_fixed(register gs_state *pgs, fixed px, fixed py)
  325. {    double fpx = fixed2float(px);
  326.     double fdx = fpx - pgs->ctm.tx;
  327.     double fpy = fixed2float(py);
  328.     double fdy = fpy - pgs->ctm.ty;
  329.     fixed dx, dy;
  330.     int code;
  331.  
  332.     if ( pgs->ctm.txy_fixed_valid )
  333.       {    dx = float2fixed(fdx);
  334.         dy = float2fixed(fdy);
  335.         code = gx_path_translate(pgs->path, dx, dy);
  336.         if ( code < 0 )
  337.           return code;
  338.         if ( pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid )
  339.           pgs->char_tm.tx_fixed += dx,
  340.           pgs->char_tm.ty_fixed += dy;
  341.       }
  342.     else
  343.       {    if ( !gx_path_is_null(pgs->path) )
  344.           return_error(gs_error_limitcheck);
  345.       }
  346.     pgs->ctm.tx = fpx;
  347.     pgs->ctm.tx_fixed = px;
  348.     pgs->ctm.ty = fpy;
  349.     pgs->ctm.ty_fixed = py;
  350.     pgs->ctm.txy_fixed_valid = true;
  351.     pgs->ctm_inverse_valid = false;
  352.     if ( pgs->char_tm_valid )
  353.     {    /* Update char_tm now, leaving it valid. */
  354.         pgs->char_tm.tx += fdx;
  355.         pgs->char_tm.ty += fdy;
  356.     }
  357. #ifdef DEBUG
  358. if ( gs_debug_c('x') )
  359.     dprintf2("[x]translate_to_fixed %g, %g:\n",
  360.          fixed2float(px), fixed2float(py)),
  361.     trace_ctm(pgs),
  362.     dprintf("[x]   char_tm:\n"),
  363.     trace_matrix_fixed(&pgs->char_tm);
  364. #endif
  365.     return 0;
  366. }
  367.  
  368. /* Scale the CTM and character matrix for oversampling. */
  369. int
  370. gx_scale_char_matrix(register gs_state *pgs, int sx, int sy)
  371. {
  372. #define scale_cxy(s, vx, vy)\
  373.   if ( s != 1 )\
  374.    {    pgs->ctm.vx *= s;\
  375.     pgs->ctm.vy *= s;\
  376.     pgs->ctm_inverse_valid = false;\
  377.     if ( pgs->char_tm_valid )\
  378.     {    pgs->char_tm.vx *= s;\
  379.         pgs->char_tm.vy *= s;\
  380.     }\
  381.    }
  382.     scale_cxy(sx, xx, yx);
  383.     scale_cxy(sy, xy, yy);
  384. #undef scale_cxy
  385.     if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
  386.     return 0;
  387. }
  388.  
  389. /* Compute the coefficients for fast fixed-point distance transformations */
  390. /* from a transformation matrix. */
  391. /* We should cache the coefficients with the ctm.... */
  392. int
  393. gx_matrix_to_fixed_coeff(const gs_matrix *pmat, register fixed_coeff *pfc,
  394.   int max_bits)
  395. {    gs_matrix ctm;
  396.     int scale = -10000;
  397.     int expt, shift;
  398.     ctm = *pmat;
  399.     pfc->skewed = 0;
  400.     if ( !is_fzero(ctm.xx) )
  401.        {    discard(frexp(ctm.xx, &scale));
  402.        }
  403.     if ( !is_fzero(ctm.xy) )
  404.        {    discard(frexp(ctm.xy, &expt));
  405.         if ( expt > scale ) scale = expt;
  406.         pfc->skewed = 1;
  407.        }
  408.     if ( !is_fzero(ctm.yx) )
  409.        {    discard(frexp(ctm.yx, &expt));
  410.         if ( expt > scale ) scale = expt;
  411.         pfc->skewed = 1;
  412.        }
  413.     if ( !is_fzero(ctm.yy) )
  414.        {    discard(frexp(ctm.yy, &expt));
  415.         if ( expt > scale ) scale = expt;
  416.        }
  417.     scale = sizeof(long) * 8 - 1 - max_bits - scale;
  418.     shift = scale - _fixed_shift;
  419.     if ( shift > 0 )
  420.        {    pfc->shift = shift;
  421.         pfc->round = (fixed)1 << (shift - 1);
  422.        }
  423.     else
  424.        {    pfc->shift = 0;
  425.         pfc->round = 0;
  426.         scale -= shift;
  427.        }
  428. #define set_c(c)\
  429.   if ( is_fzero(ctm.c) ) pfc->c.f = 0, pfc->c.l = 0;\
  430.   else pfc->c.f = ldexp(ctm.c, _fixed_shift), pfc->c.l = (long)ldexp(ctm.c, scale)
  431.     set_c(xx);
  432.     set_c(xy);
  433.     set_c(yx);
  434.     set_c(yy);
  435. #ifdef DEBUG
  436. if ( gs_debug_c('x') )
  437.    {    dprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
  438.          ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
  439.     dprintf6("   scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
  440.          scale, pfc->xx.l, pfc->xy.l, pfc->yx.l, pfc->yy.l,
  441.          pfc->shift);
  442.    }
  443. #endif
  444.     pfc->max_bits = max_bits;
  445.     return 0;
  446. }
  447.  
  448. /* ------ Debugging printout ------ */
  449.  
  450. #ifdef DEBUG
  451.  
  452. /* Print a matrix */
  453. private void near
  454. trace_matrix_fixed(const gs_matrix_fixed *pmat)
  455. {    trace_matrix((const gs_matrix *)pmat);
  456.     if ( pmat->txy_fixed_valid )
  457.       {    dprintf2("\t\tt_fixed: [%6g %6g]\n",
  458.              fixed2float(pmat->tx_fixed),
  459.              fixed2float(pmat->ty_fixed));
  460.       }
  461.     else
  462.       {    dputs("\t\tt_fixed not valid\n");
  463.       }
  464. }
  465. private void near
  466. trace_matrix(register const gs_matrix *pmat)
  467. {    dprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
  468.          pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
  469. }
  470.  
  471. #endif
  472.